package leetcode;

/**
 * 647. 回文子串
 * 给你一个字符串 s ，请你统计并返回这个字符串中 回文子串 的数目。
 * <p>
 * 回文字符串 是正着读和倒过来读一样的字符串。
 * <p>
 * 子字符串 是字符串中的由连续字符组成的一个序列。
 * <p>
 * 具有不同开始位置或结束位置的子串，即使是由相同的字符组成，也会被视作不同的子串。
 * <p>
 * <p>
 * <p>
 * 示例 1：
 * <p>
 * 输入：s = "abc"
 * 输出：3
 * 解释：三个回文子串: "a", "b", "c"
 * 示例 2：
 * <p>
 * 输入：s = "aaa"
 * 输出：6
 * 解释：6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
 */
public class CountSubstrings {

    int ans;

    /**
     * TODO 只能使用这个方法
     *
     * @param s
     * @return
     */
    public int countSubstrings0(String s) {
        int n = s.length();
        StringBuffer t = new StringBuffer("$#");
        for (int i = 0; i < n; ++i) {
            t.append(s.charAt(i));
            t.append('#');
        }
        n = t.length();
        t.append('!');

        int[] f = new int[n];
        int iMax = 0, rMax = 0, ans = 0;
        for (int i = 1; i < n; ++i) {
            // 初始化 f[i]
            f[i] = i <= rMax ? Math.min(rMax - i + 1, f[2 * iMax - i]) : 1;
            // 中心拓展
            while (t.charAt(i + f[i]) == t.charAt(i - f[i])) {
                ++f[i];
            }
            // 动态维护 iMax 和 rMax
            if (i + f[i] - 1 > rMax) {
                iMax = i;
                rMax = i + f[i] - 1;
            }
            // 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整
            ans += f[i] / 2;
        }

        return ans;
    }


    /**
     * 奇数偶数法
     *
     * @param s
     * @return
     */
    public int countSubstrings1(String s) {
        if (s == null) {
            return 0;
        }
        if (s.length() == 1) {
            return 1;
        }

        char[] arr = s.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            speard(arr, i, i);
            speard(arr, i, i + 1);
        }
        return ans;
    }

    public void speard(char[] arr, int left, int right) {
        while (left >= 0 && right < arr.length && arr[left] == arr[right]) {
            left--;
            right++;
            ans++;
        }
    }

    /**
     * 动态规划
     *
     * @param s
     * @return
     */
    public int countSubstrings(String s) {
        if (s == null) {
            return 0;
        }
        if (s.length() == 1) {
            return 1;
        }

        char[] arr = s.toCharArray();
        // dp[i][j] 表示 i 到 j是否为回文串
        // dp[i][j] = dp[i+1][j-1] && arr[i] == arr[j];
        boolean[][] dp = new boolean[s.length()][s.length()];
        int ans = 0;

        for (int length = 2; length <= s.length(); length++) {
            for (int left = 0; left < s.length() - 1; left++) {

                int right = left + length - 1;
                if (right >= arr.length) {
                    continue;
                }

                if (arr[left] == arr[right]) {
                    if (right - left <= 2) {
                        dp[left][right] = true;
                        ans++;
                    } else if (dp[left + 1][right - 1]) {
                        dp[left][right] = true;
                        ans++;
                    }
                }
            }
        }
        return ans + arr.length;
    }
}